package main

import (
	f "fmt"
	"strconv"
)

type changfangxing struct {
	length float64
	width  float64
}

type myslice []int

type myint int

func (v myslice) sumOfSlice() int {
	sum := 0
	for _, value := range v {
		sum += value
	}
	return sum
}

func (i *myint) numadd(n int) int {
	return n + 1
}
func (c *changfangxing) area() float64 {
	return c.length * c.width
}

type person struct {
	name string
	age  int
}

func (p person) setname(name string) {
	p.name = name
}
func (p *person) setage(age int) {
	p.age = age
}
func (p *person) getname() string {
	return p.name
}
func (p *person) getage() int {
	return p.age
}
func (p *person) speak() {
	f.Println("speak in person")
}
func (p *Admin) speak() {
	f.Println("speak in admin")
}

type Admin struct {
	person
	a int
}

type book struct {
	name  string
	price int
}
type booktype struct {
	bo       *book
	nametype string
}

func (bkt *booktype) speak() {
	f.Printf("speak in booktype name %s \n", bkt.nametype)
}

func (b *book) speak() {
	f.Printf("speak in book name %s - price %d \n", b.name, b.price)
}

func (b *book) String() string {
	return b.name + " : " + strconv.Itoa(b.price)
}

func main() {
	c := changfangxing{
		2.5,
		4.0,
	}
	f.Printf("%f\n", c.area())
	n := new(myint)
	f.Println(n.numadd(0))

	s := myslice{10, 20, 30}
	f.Println(s.sumOfSlice())

	//除了实例有值类型和指针类型的区别，方法也有值类型的方法和指针类型的区别
	//Go中所有需要的传值的时候，都是按值传递的，也就是拷贝一个副本
	//只要receiver(接收)是值类型的，无论是使用值类型的实例还是指针类型的实例
	//都是拷贝整个底层数据结构，方法内部访问的和修改的都是实例的副本
	//只要receiver(接收)是指针类型的，无论是使用值类型的实例还是指针类型的实例
	//都是拷贝指针，方法内部访问的和修改的都是原始实例的副本
	p1 := new(person)
	p1.setname("long1")
	p1.setage(21)
	f.Println(p1.getname())
	f.Println(p1.getage())

	p2 := person{}
	p2.setname("long2")
	p2.setage(22)
	f.Println(p2.getname())
	f.Println(p2.getage())
	//嵌套struct
	//当内部struct嵌套进外部struct时，
	//内部struct方法也会被嵌套，
	//也就是说外部struct拥有了内部struct的方法

	a := new(Admin)
	//直接调用内部struct的方法
	a.speak()
	//间接调用内部struct的方法
	a.person.speak()

	//将一个struct作为外部struct的一个命名字段
	//	bktype := new(booktype)
	//	bktype.nametype = "悬疑类型"
	//	bktype.bo = new(book)
	//	bktype.bo.name = "冒险大世界"
	//	bktype.bo.price = 200
	//或者
	bktype := &booktype{&book{"冒险大世界", 200}, "悬疑类型"}
	//调用属于book的方法speak()
	bktype.bo.speak()
	bktype.speak()

	//多种继承看自己需要

	//重写string方法
	bb := new(book)
	bb.name = "冒险大世界"
	bb.price = 200
	f.Println(bb)

}
